#-*- coding.utf-8 -*-
'''
视频和音频素材信息以json类型数据格式输入
示例
{
    "video_type" : "4"  取值：""为所有视频顺序衔接，"4"为4个视频2*2矩阵式同时播放，"2"为2个视频1行*2列式同时播放
    ,"video_dict" : {
        "0.mp4":["00:00:03,00:00:10","00:00:36,00:01:32.30"]
        ,"1.mkv":["00:00:02,00:01:22","00:00:36,00:01:32.30"]
        ,"2.mkv":["00:00:36,00:01:32.30","00:00:36,00:01:32.30","00:00:36,00:01:32.30"]
    }

    ,"audio_dict" : {
        "audioname1.mp3":[]
        ,"audioname2.mp3":[]
    }

    ,"trans_dict" : ["dfs.mp4","fds.mp4","gre.mp4"
    ]

    ,"head_video":"aaa.mp4"
    ,"tail_video":"bb.mp4"
    ,"bgm":"bb.mp4"

}
'''
demo_json_str = ''
VIDEO_DIR = 'C:/E/temp/video/'
AUDIO_DIR = ''
NEW_VIDEO = 'C:/E/temp/video/%s.mp4'
THREADS_NUM = 8
VIDEO_SIZE = (1280,720)
GLOBAL_WIDTH = 1280
GLOBAL_HEIGHT = 720
import json,os,time
from moviepy.editor import VideoFileClip,AudioFileClip,concatenate_videoclips,clips_array,TextClip,afx,CompositeVideoClip,ImageClip

'''
def getJsonObjFromInfoStr(infoJson:str):
    return json.loads(jsonObj)
'''
#剪切视频 得到需要拼接的视频list集合
def getClippedVideoListFromSourceVideos(jsonObj:object,withSourceAudio=1):
    sourceVideosDict = jsonObj['video_dict']
    clipList = []
    for sourceVideo,cutTimes in sourceVideosDict.items():
        currentVideo = VideoFileClip(os.path.join(VIDEO_DIR,sourceVideo))
        if withSourceAudio != 1 :
            currentVideo = currentVideo.without_audio()
        if len(cutTimes) == 0 :
            clipList.append(currentVideo)
            continue
        for timeStr in cutTimes:
            start_end_group = timeStr.split(',')
            clipList.append(currentVideo.subclip(start_end_group[0],start_end_group[1]))
    return clipList

#给视频加文字
#_video_source:源视频
#_text:要添加的文本
#_text_duration:文本持续的时间
#_text_font_size=70:字体大小
#_text_color='white':字体颜色
#_text_pos='center':字体位置
def addMaskTextOnVideo(_video_source,_text,_text_duration=None,_text_font_size=70,_text_color='white',_text_pos='center',_opacity=1):
    clip = VideoFileClip(_video_source)
    # 做一个txt clip. 自定义样式，颜色.
    txt_clip = TextClip(_text,font='simsun.ttc',fontsize=_text_font_size,color=_text_color)
    # 文本clip在屏幕正中显示持续_text_duration秒
    if _text_duration is None:
        _text_duration = clip.duration
    txt_clip = txt_clip.set_pos(_text_pos).set_duration(_text_duration)
    return CompositeVideoClip([clip, txt_clip])

#生成要加载在视频上的图片
def generateMaskImageOnVideo(img:str,img_duration=5,img_size=(50,100),opacity=0.5,position=('right','top')):
    logo = (ImageClip(img)
            .set_duration(img_duration)
            .resize(img_size)
            .margin(opacity=opacity)
            .set_pos(position))
    return logo


#创建连续视频
def createVideoUseClipped(clippedVideoList,whsize=(GLOBAL_WIDTH,GLOBAL_HEIGHT),bgmAudioList=[],transitionVideoList=[],headVideo='',tailVideo=''):
    #需要重新设置尺寸（宽高比）
    vl = []
    for v in clippedVideoList:
        vl.append(v.resize(whsize))
    return concatenate_videoclips(vl)

#创建4幅视频
def createFourVideoCompositeUseClipped(clippedVideoList,whsize=(GLOBAL_WIDTH,GLOBAL_HEIGHT)):
    if len(clippedVideoList) != 4 :
        return None
    vl=[]
    width = int(whsize[0]/2)
    height = int(whsize[1]/2)
    for v in clippedVideoList:
        vl.append(v.resize((width,height)))
    return clips_array([[vl[0],vl[1]],[vl[2],vl[3]]]).resize(whsize)
         
#创建2幅视频
def createTwoVideoCompositeUseClipped(clippedVideoList,whsize=(GLOBAL_WIDTH,GLOBAL_HEIGHT)):
    if len(clippedVideoList) < 2 :
        return None
    width = int(whsize[0]/2)
    height = int(whsize[1]/2)
    vl = resizeVideoList(clippedVideoList,(width,height))
    if len(clippedVideoList) == 2 :
        return clips_array([[vl[0],vl[1]]]).resize(whsize)
    else :
        backVideo = clippedVideoList[2]
        topVideo = clips_array([[vl[0],vl[1]]]).set_pos('center').set_duration(backVideo.duration)
        return CompositeVideoClip([backVideo.resize(whsize),topVideo])

#提取视频的音频 返回音频对象实例
def getAudioFromVideo(videoFile:str):
    return AudioFileClip(videoFile)
#给视频添加音频 返回视频对象实例
def addAudioOnVideo(videoFile:str,audioFile:str):
    video = AudioFileClip(videoFile)
    videoDuration = video.duration
    audio = AudioFileClip(audioFile)
    audioClip = afx.audio_loop(audio,duration=videoDuration)
    return video.set_audio(audioClip)
#给视频添加音频 返回视频对象实例
def addAudioOnVideoObj(video:VideoFileClip,audio:AudioFileClip):
    videoDuration = video.duration
    audioClip = afx.audio_loop(audio,duration=videoDuration)
    return video.set_audio(audioClip)

#重置list列表中video的尺寸
def resizeVideoList(vlist:list,whtuple:tuple)->list:
    vl = []
    for v in vlist:
        vl.append(v.resize(whtuple))
    return vl
#改变视频播放速度 返回视频对象实例
def changeVideoRate(video:VideoFileClip,multiple):
    duration = video.duration
    return video.fl_time(lambda t:multiple*t,
            apply_to=['mask','video','audio']).set_end(duration/multiple)
#保存视频
def saveVideo(clip,fileName):
    clip.write_videofile(fileName,threads=THREADS_NUM)

#主函数
def mainFunc():
    #当前日期、时刻
    file_name = time.strftime('%Y-%m-%d-%H%M%S',time.localtime())
    with open('videoinfo.json','r',encoding='utf-8') as f:
        demo_json_str = f.read()
    infoObj = json.loads(demo_json_str)
    withSourceAudio = 1
    if infoObj['bgm'] != '':
        withSourceAudio = 0
    clippedVideoList = getClippedVideoListFromSourceVideos(infoObj,withSourceAudio=withSourceAudio)
    finalVideo = None
    if infoObj['video_type']=='':
        finalVideo = createVideoUseClipped(clippedVideoList)
    if infoObj['video_type']=='4' and len(clippedVideoList)>=4:
        finalVideo = createFourVideoCompositeUseClipped(clippedVideoList)
    if infoObj['video_type']=='2' and len(clippedVideoList)>=2:
        finalVideo = createTwoVideoCompositeUseClipped(clippedVideoList)
    if infoObj['bgm']!='':
        finalVideo = addAudioOnVideoObj(finalVideo,AudioFileClip(VIDEO_DIR+infoObj['bgm']))
    if finalVideo :
        saveVideo(finalVideo,VIDEO_DIR+file_name+'.mp4')

if __name__ == '__main__':
    mainFunc()
